/**
 * 
 */
CodeMirror.defineMode("template", function(config, parserConfig) {
	var _REGEX_ = /{[{%#]([^{]*)[}%#]}/;
	// TODO: add position info
	function eatOne(stream) {
		return eatTill(stream, _REGEX_);
	}

	function eatTill(stream, regex) {
		var str = getRemainingString(stream);
		var results = regex.exec(str), prefix = null, token = null;
		if (!results) {
			prefix = str;
		} else {
			var index = results.index;
			if (index > 0) {
				prefix = str.substring(0, index);
				str = str.substring(index);
			}
			token = results[0];
		}
		return {
			prefix : prefix,
			token : token
		};
	}

	function getRemainingString(stream) {
		return stream.string.substring(stream.start);
	}

	function advanceStream(stream, len) {
		for ( var i = 0; i < len; i++)
			stream.next();
	}

	return {
		startState : function(basecolumn) {
			return {
				current : 'text'
			};
		},

		token : function(stream, state) {
			var result = eatTill(stream, (state.current == 'text'? _REGEX_ :  /[}%#]}/));
			if (state.current == 'text') {
				if (result.prefix) {
					advanceStream(stream, result.prefix.length);
					return null;
				} else if (result.token) {
					var m = null, token = result.token;
					if ((m = token.match(/{#(.*)#}/))) {
						state.current = 'comment';
					} else if ((m = token.match(/{{(.*)}}/))) {
						state.current = 'var';
					} else if (m = token.match(/{%(.*)%}/)) {
						state.current = 'block';
					}
					advanceStream(stream, 2);
					return 'directive';
				}
			} else {
				if (result.prefix) {
					advanceStream(stream, result.prefix.length);
					return state.current;
				} else if (result.token) {
					advanceStream(stream, 2);
					state.current = 'text';
					return 'directive';
				}
			}
		}

	};
});